package com.lijie.ljblog.socketAPI;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.api.R;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lijie.ljblog.chess.*;
import com.lijie.ljblog.enums.ChessColorEnum;
import com.lijie.ljblog.model.Person;
import com.lijie.ljblog.model.vo.ChessResponseVO;
import com.lijie.ljblog.model.vo.GamePVPGoPangResponseVO;
import com.lijie.ljblog.model.vo.MatchResponseVO;
import com.lijie.ljblog.util.GoBangBotUtil;
import com.lijie.ljblog.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description 人人对战webSocket
 * @Author lijie
 * @Date 2022/8/26 16:32
 **/
@Slf4j
@Component
public class PVPGameAPI extends TextWebSocketHandler {
    private ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private RoomManager roomManager;

    @Autowired
    OnlineUserManager onlineUserManager;

    /**
     * 建立连接，初始化一个游戏房间
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        MatchResponseVO response = new MatchResponseVO();
        Integer userId = GoBangBotUtil.getUserId(session);
        if(ObjectUtils.isEmpty(userId)){
            response.error("未登录！请登陆后进行匹配开始游戏");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return ;
        }
        ChessGameRoom roomByUserId = roomManager.getRoomByUserId(userId);
        if(ObjectUtils.isEmpty(roomByUserId)){
            //没有匹配成功，无游戏房间 报错
            response.error("没有匹配的对局！");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return ;
        }
        if (onlineUserManager.getGameRoomSession(userId) != null){
            response.error("当前游戏禁止多开");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            return;
        }
        log.info("玩家"+userId+"进入游戏房间"+roomByUserId.getRoomId());
        //将游戏房间会话加入管理器中
        onlineUserManager.enterGameRoom(userId,session);

        //等待两个玩家进入战局
        synchronized (roomByUserId){
            if(ObjectUtils.isEmpty(roomByUserId.getPlayerOneId())){
                roomByUserId.setPlayerOneId(userId);
                //玩家1准备就绪。
                response.success("info","准备就绪，等待对方进入房间");
                response.setOpponentName(roomByUserId.getOpponent().get(userId).getUserName());
                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
                log.info("玩家1"+userId+"已准备就绪");
                return ;
            }
            if(ObjectUtils.isEmpty(roomByUserId.getPlayerTwoId())){
                roomByUserId.setPlayerTwoId(userId);
                //玩家2准备就绪。
                response.success("info","双方都进入房间，准备开始游戏");
                Thread.sleep(1000);
                //通知双方准备就绪
                WebSocketSession sessionUserOne = onlineUserManager.getGameRoomSession(roomByUserId.getPlayerOneId());
                sessionUserOne.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));

                response.setOpponentName(roomByUserId.getOpponent().get(userId).getUserName());
                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
                log.info("玩家2"+userId+"已准备就绪，双方都进入房间，准备开始游戏");
            }
        }
        //睡一秒后通知玩家先后手情况并可以落子。
        Thread.sleep(1000);
        //开始游戏
        beginGame(roomByUserId,roomByUserId.getPlayerOneId());
        beginGame(roomByUserId,roomByUserId.getPlayerTwoId());
    }

    /**
     * 玩家落子
     * @param session
     * @param message
     * @throws Exception
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        Integer userId = GoBangBotUtil.getUserId(session);
        //通过userId获取游戏房间
        ChessGameRoom chessGameRoom = roomManager.getRoomByUserId(userId);
        ChessPoint chessPoint = JSON.parseObject(message.getPayload(), ChessPoint.class);
        //棋子颜色
        ChessColorEnum chessColor = chessGameRoom.getPlayerColor().get(userId);
        int[][] chessBoard = chessGameRoom.getChess().getChessBoard();
        if(chessBoard[chessPoint.getX()][chessPoint.getY()] != 0){
            log.error("该处不能落子");
            return;
        }
        //获得当前游戏棋盘
        Chess chess = chessGameRoom.getChess();
        //玩家落子
        chess.putChess(chessColor,chessPoint.getX(),chessPoint.getY());
        //响应结果
        GamePVPGoPangResponseVO chessResponseVO = new GamePVPGoPangResponseVO(chessPoint.getX(),chessPoint.getY(),chessColor);
        chessResponseVO.setReason("playing");
        //判断游戏是否结束
        boolean b = chess.checkWinner(chessColor, chessPoint.getX(), chessPoint.getY());
        if(b){
            //有玩家胜利，该局游戏结束
            //设置胜利方棋子颜色
            chessResponseVO.setWinnerUserId(userId);
            chessResponseVO.setOver(true);
            //销毁房间
            roomManager.remove(chessGameRoom.getPlayerOneId(),chessGameRoom.getPlayerTwoId(),chessGameRoom.getRoomId());

        }
        WebSocketSession gameRoomSessionOne = onlineUserManager.getGameRoomSession(chessGameRoom.getPlayerOneId());
        WebSocketSession gameRoomSessionTwo = onlineUserManager.getGameRoomSession(chessGameRoom.getPlayerTwoId());
        gameRoomSessionOne.sendMessage(new TextMessage(objectMapper.writeValueAsString(chessResponseVO)));
        gameRoomSessionTwo.sendMessage(new TextMessage(objectMapper.writeValueAsString(chessResponseVO)));
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
    }

    /**
     * 用户关闭连接，删除用户游戏房间和用户会话
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        Integer userId = GoBangBotUtil.getUserId(session);
        if (!ObjectUtils.isEmpty(userId)) {
            onlineUserManager.exitGameRoom(userId);
            log.info("玩家id" + userId + "离开游戏房间");
        } else {
            log.info("[afterConnectionClosed]当前用户尚未登录");
        }
    }

    /**
     * 通知房间内的两个玩家准备就绪，可以落子
     * @param roomByUserId
     */
    private  void beginGame(ChessGameRoom roomByUserId,Integer playerId) throws IOException {
        Map<Integer, ChessColorEnum> playerColor = roomByUserId.getPlayerColor();
        WebSocketSession gameRoomSession = onlineUserManager.getGameRoomSession(playerId);
        //给玩家1 发送消息可以开始游戏
        GamePVPGoPangResponseVO matchResponseOne = new GamePVPGoPangResponseVO();
        ChessColorEnum chessColorEnum = playerColor.get(playerId);
        matchResponseOne.success("begin",String.valueOf(chessColorEnum.getVal()));
        matchResponseOne.setColor(chessColorEnum.getVal());
        gameRoomSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(matchResponseOne)));

    }
}
